//工厂模式: 对象类型不明确
function createPerson(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };
    return o;
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
person1.constructor; //Object
//构造函数模式
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    //即使公共方法每个实例也会重复定义
    //可以将函数在全局声明，在构造函数里引用
    this.sayName = function(){
        alert(this.name);
    };
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
//原型模式
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
}
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person("Nicholas", 29, "Software Engineer");
person1.sayName(); //"Nicholas"
//判断实例的原型(实例的原型指向调用isPrototypeOf函数的对象(原型)
alert(Person.prototype.isPrototypeOf(person1)); //true
//获取对象的原型(对象)
alert(Object.getPrototypeOf(person1) == Person.prototype); //true
//创建私有属性sayName, 不影响原型
person1.sayName = "Nicholas"; 
var person2 = new Person("Lys", 26, "IT Devloper");
person1.sayName; // "Nicholas"
person2.sayName();
//删除实例自定义属性
delete person1.sayName;
person1.sayName();
delete person1.sayName; //原型属性不能删除
person1.sayName();
alert(person1.hasOwnProperty("name")); //true
alert(person1.hasOwnProperty("sayName")); //false
alert("name" in person1); //true
alert("sayName" in person1); //true

//字面量定义原型
//这里的prototype 实际上是通过Object构建的对象,这个对象的原型的constructor指向Object, 最终导致Person的实例的constructor指向Object
//因此通过constructor获取的构造函数不一定准确
Person.prototype = {
    //[[prototype]] -->constructor--->Object
    sayName : function () {
        alert(this.name);
    }
};
var person3 = new Person("p3", 13, "Student");
person3.constructor == Object; //true
Person.prototype = {
    sayName : function () {
        alert(this.name); 
    },   
    constructor: Person
}
person3 = new Person("p3", 13, "Student");
//constructor可遍历
for(var x in person3) {
	if(x == "constructor") {
		console.log(x);
	}
}
//重新修正为不可遍历
Object.defineProperty(Person.prototype, "constructor", {
    enumerable: false,
    //value: Person
});

//将原型封装在构造函数中
function Person(name, age, job){
	//私有(自定义)属性
	this.name = name;
	this.age = age;
	this.job = job;
	//只在第一次实例化时定义原型方法
	//不能使用字面量定义原型，否则首个实例不能获取原型属性
	if (typeof this.sayName != "function"){
		Person.prototype.sayName = function(){
			alert(this.name);
		};
	}
}
//创建私有(内部)属性
//Person的活动对象会得到保存
function Person(name, age, job){
	//创建要返回的对象
	var o = {};
	o.age = age;
	o.job = job;
	o.sayName = function(){
		alert(name);
	};
	return o;
}
var friend = Person("Nicholas", 29, "Software Engineer");
friend.sayName(); //"Nicholas"
friend instanceof Person; //false

//寄生构造函数模式
function SpecialArray(){
	//创建数组
	var values = new Array();
	//添加值(动态传参)
	values.push.apply(values, arguments);
	//添加方法
	values.toPipedString = function(){
		return this.join("|");
	};
	//返回数组
	return values;
}
var colors = new SpecialArray("red", "blue", "green");
alert(colors.toPipedString()); //"red|blue|green"
colors instanceof SpecialArray; //fasle
var myColors = SpecialArray("red", "blue", "green");
myColors.constructor === colors.constructor; //true: Array
myColors instanceof SpecialArray; //false

/*******继承BEGIN********/
//原型链
//Function-->Function.prototype
Function.prototype === Object.getPrototypeOf(Function);
//function-->Function.prototype--->Object.prototype
Object.getPrototypeOf(Function.prototype) ===
    Object.prototype; //true
//fobj --->f.prototype--->Object.prototype
function f(){}
var fobj = new f();
Object.getPrototypeOf(fobj) === f.prototype;
f.prototype.constructor === f;
Object.getPrototypeOf(f.prototype) === Object.prototype;
//Object--->xxx---Object.prototype
Object.getPrototypeOf(Object.getPrototypeOf(Object)) === 
    Object.prototype; //true
//array ---> Array.prototype--->Object.prototype
Object.getPrototypeOf(Array.prototype) === 
    Object.prototype;
//obj --> Object.prototype
//Object.prototype ---> null
Object.getPrototypeOf(Object.prototype); //null

//最优继承：组合寄生继承
//生成原型为父类原型，但不包含父类私有(自定义)属性的实例对象,使用时传入父类原型
function object(o){ 
	function F(){}
	F.prototype = o;
	return new F();
}
//在继承父类原型实例的基础上定义子类原型属性，最后将该实例作为子类原型
function inheritPrototype(subType, superType){
	//var prototype = Object.create(superType.prototype);
	var prototype = object(superType.prototype); //创建对象
	prototype.constructor = subType; //增强对象
	subType.prototype = prototype; //指定对象
}
//父类
function SuperType(name){
	this.name = name;
	this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
	alert(this.name);
};
//子类
function SubType(name, age){
	SuperType.call(this, name);
	this.age = age;
}
//继承
inheritPrototype(SubType, SuperType);
//必须先继承，才能对原型的属性进行修改，不能直接修改原型
SubType.prototype.sayAge = function(){
	alert(this.age);
};

//简单原继承,将父类的实例作为子类实例的原型
//缺点1:父类的私有(自定义)属性会被子类共享，或者需要子类重写这些属性(一个属性需要两次初始化)
//缺点2：？(不能在子类构造函数中向父类传参)
SubType.prototype = new SuperType();

//组合继承(基本+构造函数)
//借用构造函数
//缺点：?
function SubType(){
	// 继承了 SuperType的实例私有属性
	SuperType.call(this[,...]);
}
//继承方法
//组合继承避免了原型链和借用构造函数的缺陷
//缺点: 重复继承了属性
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;

//原型式继承:将父类的原型作为子类原型的原型
//Object.create(prototypeObj[,{defineProperties...} ]
//一个用作新对象原型的对象和（可选的）一个为新对象定义额外属性的对象
var anotherPerson = Object.create(person, {
	name: {
		value: "Greg"
	}
});

//寄生式继承
function createAnother(original){
	//通过调用函数创建一个新对象
	var clone = object(original);
	//clone = Object.create(original);  
	clone.sayHi = function(){ //以某种方式来增强这个对象
		alert("hi");
	};
	return clone; //返回这个对象
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"

/*******继承END********/


/*****列出所有属性BEGIN******/
var person = {
    firstName: "Bill",
    lastName : "Gates"
    language : "EN" 
};

Object.defineProperty(person, "language", {enumerable:false});
//可枚举属性
Object.keys(person); //[firstName, lastName]
//枚举属性
Object.getOwnPropertyNames(person);  // [firstName, lastName, language]
/*****列出所有属性END******/

